﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using SharedGenomics.Core;
using SharedGenomics.Annotations;
using SharedGenomics.Workbench.Annotations;

namespace SharedGenomics.Workbench.Tests.Annotations
{
    [TestClass]
    public class AnnotationRequestQueueTests
    {
        [TestMethod]
        public void ShouldExecuteRequests()
        {
            //setup a pipeline with a single stage that records the number of times it is executed
            var pipeline = new AnnotationRequestPipeline();
            var recordStage = new RecordingAnnotationRequestStage();
            pipeline.AddRequestStage(recordStage);
            pipeline.Fix();

            var queue = new SharedGenomics.Workbench.Annotations.AnnotationRequestQueue(pipeline);

            //create queue and 10 threads each of which will place 1000 items in the queue
            ParameterizedThreadStart threadFunc = si =>
            {
                var request = new AnnotationRequestInfo { Key = AnnotationKey.GoogleSearch, RootValue = "rs001" };
                1000.Times(() => queue.QueueRequest(request));
            };

            var threads = Enumerable.Range(0, 10).Select(i => new Thread(threadFunc)).ToList();
            threads.ForEach(t => t.Start());

            //wait for all threads to finish
            threads.ForEach(t => t.Join());

            //stage should have been executed 10000 times
            Thread.Sleep(5000);
            Assert.AreEqual(10000, recordStage.CalledCount);
        }

        private class RecordingAnnotationRequestStage : IAnnotationRequestStage
        {
            private int _calledCount = 0;

            public int CalledCount
            {
                get { return this._calledCount; }
            }

            public void Process(AnnotationRequestContext context, IAnnotationRequestPipelineTraversalStrategy traversalStrategy)
            {
                Interlocked.Increment(ref this._calledCount);
                traversalStrategy.MoveNext(context);
            }
        }
    }
}
